<template>
  <div class="upload-button-content">
    <el-button
      v-if="roundFlag"
      type="primary"
      id="uploadButton"
      :size="size"
      @click="uploadDialogVisible = true"
    >
      <i class="el-icon-upload el-icon--right" /> 上传
    </el-button>
    <el-button v-if="circleFlag" size="size" id="uploadButton" circle>
      <i class="el-icon-upload" />
    </el-button>
    <div>
      <el-dialog
        title="文件上传"
        :visible.sync="uploadDialogVisible"
        width="30%"
        :modal="false"
        :append-to-body="true"
        @opened="rebindUploader"
        center
      >
        <div class="upload-content" id="upload-content">
          <div class="drag-content">
            <div class="drag-icon-content">
              <i class="el-icon-upload drag-icon"></i>
            </div>
            <div class="drag-text-content">
              <el-link :underline="false" type="info"
                >将文件拖到此处,或</el-link
              >
              <el-link :underline="false" type="primary">点击上传</el-link>
            </div>
          </div>
        </div>
      </el-dialog>
    </div>
  </div>
</template>

<script>
import Uploader from "simple-uploader.js";
import { getToken } from "../../../utils/cookie";
import panUtil from "../../../utils/common";
import { MD5 } from "../../md5";
import fileService from "../../../api/file";
import { mapActions, mapGetters, mapMutations } from "vuex";

export default {
  name: "uploadButton",
  components: {},
  props: {
    roundFlag: Boolean,
    circleFlag: Boolean,
    size: String,
  },
  data() {
    return {
      // 详细文档地址：https://github.com/simple-uploader/Uploader/blob/develop/README_zh-CN.md#%E9%85%8D%E7%BD%AE
      fileOptions: {
        target: function(file, chunk) {
          if (panUtil.getChunkSize() && panUtil.getChunkSize() > 0) {
            return panUtil.getUrlPrefix() + "/file/chunk-upload";
          }
          return panUtil.getUrlPrefix() + "/file/upload";
        },
        singleFile: !panUtil.getChunkSize() || panUtil.getChunkSize() <= 0,
        chunkSize: panUtil.getChunkSize(),
        forceChunkSize: false,
        simultaneousUploads: 3,
        fileParameterName: "file",
        query: function(file, chunk) {
          return {};
        },
        headers: {
          Authorization: getToken(),
        },
        checkChunkUploadedByResponse: function(chunk, message) {
          let objMessage = {};
          try {
            objMessage = JSON.parse(message);
          } catch (e) {}
          // fake response
          // objMessage.uploaded_chunks = [2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 17, 20, 21]
          // check the chunk is uploaded
          return (
            (objMessage.data.uploadedChunks || []).indexOf(chunk.offset + 1) >=
            0
          );
        },
        maxChunkRetries: 0,
        chunkRetryInterval: null,
        progressCallbacksInterval: 500,
        successStatuses: [200, 201, 202],
        permanentErrors: [404, 415, 500, 501],
        initialPaused: false,
      },
      uploader: undefined,
      uploadDialogVisible: false,
      assignFlag: false,
    };
  },
  methods: {
    ...mapMutations({
      clearTaskList: "task/clear",
      addTaskItem: "task/add",
      removeTaskItem: "task/remove",
      updateTaskStatus: "task/updateStatus",
      updateTaskProcess: "task/updateProcess",
      getUploadTask: "task/getTask",
      updateTaskListViewFlag: "task/updateViewFlag",
    }),
    ...mapActions({
      reloadFileList: "file/loadFileList",
    }),
    rebindUploader() {
      if (!this.uploader.support)
        this.$message.error("本浏览器不支持simple-uploader，请更换浏览器重试");
      if (!this.assignFlag) {
        this.uploader.assignBrowse(document.getElementById("upload-content"));
        this.uploader.assignDrop(document.getElementById("upload-content"));
        this.assignFlag = true;
      }
    },
    initUploader() {
      this.clearTaskList();
      // 实例化一个上传对象
      this.uploader = new Uploader(this.fileOptions);
      // 如果不支持 需要降级的地方
      if (!this.uploader.support)
        this.$message.error("本浏览器不支持simple-uploader，请更换浏览器重试");
      // this.uploader.assignBrowse(document.getElementById('drag-text'))
      // this.uploader.assignDrop(document.getElementById('upload-content'))
      // 绑定进队列
      this.uploader.on("filesAdded", this.filesAdded);
      // 绑定进度
      this.uploader.on("fileProgress", this.uploadProgress);
      // 上传成功监听
      this.uploader.on("fileSuccess", this.fileUploaded);
      // 上传全部完成调用
      this.uploader.on("complete", this.uploadComplete);
      // 上传出错调用
      this.uploader.on("fileError", this.uploadError);
    },
    filesAdded(files, fileList, event) {
      // 插件在调用该方法之前会自动过滤选择的文件 去除正在上传的文件 新添加的文件就是第一个参数files
      let _this = this;
      _this.uploadDialogVisible = false;
      try {
        files.forEach((f) => {
          f.pause();
          if (f.size > panUtil.getMaxFileSize()) {
            throw new Error(
              "文件：" +
                f.name +
                "大小超过了最大上传文件的限制（" +
                panUtil.translateFileSize(panUtil.getMaxFileSize()) +
                "）"
            );
          }
          let taskItem = {
            target: f,
            filename: f.name,
            fileSize: panUtil.translateFileSize(f.size),
            uploadedSize: panUtil.translateFileSize(0),
            status: panUtil.fileStatus.PARSING.code,
            statusText: panUtil.fileStatus.PARSING.text,
            timeRemaining: panUtil.translateTime(Number.POSITIVE_INFINITY),
            speed: panUtil.translateSpeed(f.averageSpeed),
            percentage: 0,
            parentId: new String(_this.parentId),
          };
          // 添加
          _this.addTaskItem(taskItem);
          MD5(f.file, (e, md5) => {
            f["uniqueIdentifier"] = md5;
            fileService.secUpload(
              {
                filename: f.name,
                identifier: md5,
                parentId: _this.parentId,
              },
              (res) => {
                if (res.status === 0) {
                  _this.$message.success("文件：" + f.name + " 上传完成");
                  f.cancel();
                  _this.removeTaskItem(f.name);
                  _this.reloadFileList();
                  if (_this.uploader.files.length === 0) {
                    this.updateTaskListViewFlag(false);
                  }
                } else {
                  f.resume();
                  _this.updateTaskStatus({
                    filename: f.name,
                    status: panUtil.fileStatus.WAITING.code,
                    statusText: panUtil.fileStatus.WAITING.text,
                  });
                }
              },
              (res) => {
                f.resume();
                _this.updateTaskStatus({
                  filename: f.name,
                  status: panUtil.fileStatus.WAITING.code,
                  statusText: panUtil.fileStatus.WAITING.text,
                });
              }
            );
          });
        });
      } catch (e) {
        _this.$message.error(e.message);
        _this.uploader.cancel();
        _this.clearTaskList();
        return false;
      }
      _this.updateTaskListViewFlag(true);
      return true;
    },
    uploadProgress(rootFile, file, chunk) {
      let uploadTaskItem = this.$store.getters.getUploadTask(file.name);
      if (file.isUploading()) {
        if (uploadTaskItem.status !== panUtil.fileStatus.UPLOADING.code) {
          this.updateTaskStatus({
            filename: file.name,
            status: panUtil.fileStatus.UPLOADING.code,
            statusText: panUtil.fileStatus.UPLOADING.text,
          });
        }
        this.updateTaskProcess({
          filename: file.name,
          speed: panUtil.translateSpeed(file.averageSpeed),
          percentage: Math.floor(file.progress() * 100),
          uploadedSize: panUtil.translateFileSize(file.sizeUploaded()),
          timeRemaining: panUtil.translateTime(file.timeRemaining()),
        });
      }
    },
    fileUploaded(rootFile, file, message, chunk) {
      let res = {},
        _this = this;
      try {
        res = JSON.parse(message);
      } catch (e) {}
      if (res.status === 0) {
        if (res.data.mergeFlag) {
          _this.doMerge(file);
        } else if (
          res.data.uploadedChunks &&
          res.data.uploadedChunks.length === file.chunks.length
        ) {
          _this.doMerge(file);
        }
      } else {
        file.pause();
        _this.updateTaskStatus({
          filename: file.name,
          status: panUtil.fileStatus.FAIL.code,
          statusText: panUtil.fileStatus.FAIL.text,
        });
      }
    },
    uploadComplete() {},
    uploadError(rootFile, file, message, chunk) {
      this.updateTaskStatus({
        filename: file.name,
        status: panUtil.fileStatus.FAIL.code,
        statusText: panUtil.fileStatus.FAIL.text,
      });
      this.updateTaskProcess({
        filename: file.name,
        speed: panUtil.translateSpeed(0),
        percentage: 0,
        uploadedSize: panUtil.translateFileSize(0),
        timeRemaining: panUtil.translateTime(Number.POSITIVE_INFINITY),
      });
    },
    doMerge(file) {
      let _this = this,
        uploadTaskItem = _this.$store.getters.getUploadTask(file.name);
      _this.updateTaskStatus({
        filename: file.name,
        status: panUtil.fileStatus.MERGE.code,
        statusText: panUtil.fileStatus.MERGE.text,
      });
      _this.updateTaskProcess({
        filename: file.name,
        speed: panUtil.translateSpeed(file.averageSpeed),
        percentage: 99,
        uploadedSize: panUtil.translateFileSize(file.sizeUploaded()),
        timeRemaining: panUtil.translateTime(file.timeRemaining()),
      });
      fileService.merge(
        {
          filename: uploadTaskItem.filename,
          identifier: uploadTaskItem.target.uniqueIdentifier,
          parentId: uploadTaskItem.parentId,
          totalSize: uploadTaskItem.target.size,
        },
        (res) => {
          _this.$message.success("文件：" + file.name + " 上传完成");
          _this.uploader.removeFile(file);
          _this.removeTaskItem(file.name);
          _this.reloadFileList();
          if (_this.uploader.files.length === 0) {
            this.updateTaskListViewFlag(false);
          }
        },
        (res) => {
          file.pause();
          _this.updateTaskStatus({
            filename: file.name,
            status: panUtil.fileStatus.FAIL.code,
            statusText: panUtil.fileStatus.FAIL.text,
          });
        }
      );
    },
  },
  computed: {
    ...mapGetters(["parentId"]),
  },
  mounted() {
    this.initUploader();
  },
  watch: {},
};
</script>

<style>
.upload-button-content {
  display: inline-block;
  margin-right: 10px;
}
.upload-content {
  width: 100%;
  height: 300px;
  line-height: 300px;
  display: flex;
  justify-content: center;
}
.upload-content .drag-content {
  border: 0.2em dashed #dcdfe6;
  border-radius: 1em;
  width: 80%;
  height: 250px;
  line-height: 250px;
  display: flex;
  align-items: center;
  flex-direction: column;
}

.upload-content .drag-content:hover {
  border: 0.2em dashed #409eff;
}

.upload-content .drag-content .drag-icon-content {
  height: 100px;
  line-height: 100px;
  width: 100px;
  margin-top: 25px;
}

.upload-content .drag-content .drag-icon-content .drag-icon {
  font-size: 7em;
  color: #dcdfe6;
}

.upload-content .drag-content .drag-text-content {
  display: block;
  height: 30px;
  line-height: 30px;
}
</style>
